package com.yungu.swift.order.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundTransOrderQueryModel;
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransOrderQueryRequest;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.response.AlipayFundTransOrderQueryResponse;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Sets;
import com.yungu.swift.assets.driver.model.dto.DriverCashDto;
import com.yungu.swift.assets.driver.service.DriverCashService;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.constants.FinanceConstant;
import com.yungu.swift.order.service.AliPayCashService;
import com.yungu.swift.system.finance.model.dto.FinanceWithdrawalDto;
import com.yungu.swift.system.finance.service.FinanceWithdrawalService;
import com.yungu.swift.system.sys.model.dto.SysAccountPlatformDto;
import com.yungu.swift.system.sys.service.SysAccountPlatformService;
import com.yungu.swift.utils.DateUtils;
import com.yungu.swift.utils.JsonUtils;
import com.yungu.swift.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import static com.yungu.swift.order.config.NacosListener.ALIPAY_CONFIG;
import static com.yungu.swift.order.config.NacosListener.SYS_CONFIG;

/**
 * @author : cuixiuyin
 * @date : 2020/1/16
 */
@Slf4j
@Service
public class AliPayCashServiceImpl implements AliPayCashService {

    @Reference
    private DriverCashService driverCashService;
    @Reference
    private FinanceWithdrawalService financeWithdrawalService;
    @Reference
    private SysAccountPlatformService sysAccountPlatformService;


    private static ThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern("alipay-cash-pool-%d").build();
    private static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5, threadFactory);

    public static final Set<String> FAIL_DONE_SET = Sets.newHashSet("PAYEE_NOT_EXIST", "PAYEE_USER_INFO_ERROR",
            "PAYEE_ACC_OCUPIED", "PERMIT_NON_BANK_LIMIT_PAYEE", "EXCEED_LIMIT_UNRN_DM_AMOUNT");

    @Override
    public ResponseData<Map<String, String>> toAccount(String name, String account, double amount, String serialNum) {
        try {
            Map<String, String> toaccountMap = toAccountImpl(name, account, amount, serialNum);
            // 非用户原因失败，系统重试一次
            String code = toaccountMap.get("code");
            String msg = toaccountMap.get("msg");
            boolean success = "10000".equals(code) && "SUCCESS".equalsIgnoreCase(msg);
            if (!success && !FAIL_DONE_SET.contains(toaccountMap.get("sub_code"))) {
                toaccountMap = toAccountImpl(name, account, amount, serialNum);
            }
            // 异步8秒后执行一次结果查询
            scheduledExecutorService.schedule(() -> queryCash(), 8, TimeUnit.SECONDS);
            return ResponseData.buildSuccessResponse(toaccountMap);
        } catch (AlipayApiException e) {
            log.error("AliPay toAccount AlipayApiException. serialNum={}", serialNum, e);
        } catch (JsonProcessingException e) {
            log.error("AliPay toAccount JsonProcessingException. serialNum={}", serialNum, e);
        } catch (IOException e) {
            log.error("AliPay toAccount IOException. serialNum={}", serialNum, e);
        }
        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "支付宝转账到个人账户失败");
    }

    public Map<String, String> toAccountImpl(String name, String account, double amount, String serialNum) throws IOException, AlipayApiException {
        //实例化客户端
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
        certAlipayRequest.setAppId(ALIPAY_CONFIG.getOpenAppid());
        certAlipayRequest.setPrivateKey(ALIPAY_CONFIG.getOpenBizPrivateKey());
        certAlipayRequest.setFormat("json");
        certAlipayRequest.setCharset("utf-8");
        certAlipayRequest.setSignType("RSA2");
        // D:\alipay\
        certAlipayRequest.setCertPath("/home/admin/alipay/appCertPublicKey_2021004132681237.crt");
        certAlipayRequest.setAlipayPublicCertPath("/home/admin/alipay/alipayCertPublicKey_RSA2.crt");
        certAlipayRequest.setRootCertPath("/home/admin/alipay/alipayRootCert.crt");
        AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
        AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
        AlipayFundTransToaccountTransferModel model = new AlipayFundTransToaccountTransferModel();
        model.setOutBizNo(serialNum);
        model.setPayeeType("ALIPAY_LOGONID");
        model.setPayeeAccount(account);
        model.setPayeeRealName(name);
        model.setAmount(amount + "");
        model.setPayerShowName(SYS_CONFIG.getName());
        model.setRemark("司机收入提现");
        request.setBizModel(model);
        AlipayFundTransToaccountTransferResponse response = alipayClient.certificateExecute(request);
        Map<String, Object> responseMap = JsonUtils.readValue(response.getBody(), Map.class);
        log.info("AliPay toAccount Success. serialNum={}, response={}", serialNum, response.getBody());
        Map<String, String> toaccountMap = (Map<String, String>) responseMap.get("alipay_fund_trans_toaccount_transfer_response");
        return toaccountMap;
    }


    @Override
    public ResponseData<Void> queryCash() {
        Map<String, Object> paramMap = new HashMap<>(8);
        //查询审核成功 第三方打款状态处理中的提现数据
        //支付宝提现
        paramMap.put("collectType", 3);
        //审核状态为审核成功
        paramMap.put("status", DriverCashDto.CHECK_STATUS_SUCCESS);
        //提现状态为提现中
        paramMap.put("withdrawalStatus", DriverCashDto.UNDER_WITHDRAWAL_STATUS);
        //第三方打款状态为处理中
        paramMap.put("thirdPayStatus", DriverCashDto.THIRD_STATUS_PROCESSING);
        List<DriverCashDto> driverCashDtoList = driverCashService.list(paramMap).getData();
        if (CollectionUtils.isEmpty(driverCashDtoList)) {
            log.info("没有待处理的提现信息");
            return ResponseData.buildSuccessResponse(null);
        }
        for (DriverCashDto driverCashDto : driverCashDtoList) {
            log.info("流水号：{} 查询提现开始", driverCashDto.getSerialNum());
//            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
//                    ALIPAY_CONFIG.getOpenAppid(), ALIPAY_CONFIG.getOpenBizPrivateKey(), "json", "utf-8",
//                    ALIPAY_CONFIG.getOpenBizPublicKey(), "RSA2");
            CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
            certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
            certAlipayRequest.setAppId(ALIPAY_CONFIG.getOpenAppid());
            certAlipayRequest.setPrivateKey(ALIPAY_CONFIG.getOpenBizPrivateKey());
            certAlipayRequest.setFormat("json");
            certAlipayRequest.setCharset("utf-8");
            certAlipayRequest.setSignType("RSA2");
            // D:\alipay\
            certAlipayRequest.setCertPath("/home/admin/alipay/appCertPublicKey_2021004132681237.crt");
            certAlipayRequest.setAlipayPublicCertPath("/home/admin/alipay/alipayCertPublicKey_RSA2.crt");
            certAlipayRequest.setRootCertPath("/home/admin/alipay/alipayRootCert.crt");
            AlipayFundTransOrderQueryRequest request = new AlipayFundTransOrderQueryRequest();
            AlipayFundTransOrderQueryModel model = new AlipayFundTransOrderQueryModel();
            model.setOutBizNo(driverCashDto.getSerialNum());
            request.setBizModel(model);
            try {
                AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
//                AlipayFundTransOrderQueryResponse response = alipayClient.execute(request);
                AlipayFundTransOrderQueryResponse response = alipayClient.certificateExecute(request);
                log.info("流水号：{} 查看订单返回数据", response.getBody());
                Map<String, Object> responseMap = JsonUtils.readValue(response.getBody(), Map.class);
                log.info("Alipay queryCash Success. serialNum={}, response={}", driverCashDto.getSerialNum(), response.getBody());
                Map<String, String> resultMap = (Map<String, String>) responseMap.get("alipay_fund_trans_order_query_response");
                String code = resultMap.get("code");
                String msg = resultMap.get("msg");
                boolean success = "10000".equals(code) && "SUCCESS".equalsIgnoreCase(msg);
                if (success) {
                    String payDateStr = resultMap.get("pay_date");
                    log.info("流水号：{} 提现成功，开始记录提现流水", driverCashDto.getSerialNum());
                    //打款成功时间
                    driverCashDto.setWithdrawalFinishTime(DateUtils.parse(payDateStr));
                    //获取转账手续费 单位为分 转换成元
                    driverCashDto.setThirdPoundage(0.0);
                    //记录平台流水提现和提现手续费记录
                    ResponseData<SysAccountPlatformDto> responseData = sysAccountPlatformService.getByAppid(driverCashDto.getAppid());
                    //获取平台信息
                    if (!responseData.isSuccess() || responseData.getData() == null) {
                        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到平台信息");
                    }
                    SysAccountPlatformDto accountPlatformDto = responseData.getData();
                    //获取平台初始余额
                    BigDecimal cashBalance = accountPlatformDto.getCashBalance();

                    //提现金额
                    BigDecimal amount = BigDecimal.valueOf(driverCashDto.getActualAmount());
                    //保存平台提现到支付宝的流水记录
                    FinanceWithdrawalDto financeWithdrawal = new FinanceWithdrawalDto();
                    financeWithdrawal.setUuid(StringUtils.buildUUID());
                    financeWithdrawal.setFinanceNumber(StringUtils.buildUUID());
                    financeWithdrawal.setHappenTime(new Date());
                    financeWithdrawal.setAmount(amount);
                    financeWithdrawal.setBusinessUuid(driverCashDto.getUuid());
                    financeWithdrawal.setFinanceOutflow(accountPlatformDto.getUuid());
                    financeWithdrawal.setFinanceInflow("");
                    financeWithdrawal.setCourse(FinanceConstant.WITHDRAWAL_TO_ALI);
                    financeWithdrawal.setStartBalance(cashBalance);
                    cashBalance = cashBalance.subtract(amount);
                    financeWithdrawal.setFinalBalance(cashBalance);
                    financeWithdrawal.setDescription("平台提现到司机支付宝账户支付" + amount + "元");
                    financeWithdrawal.setCreateOn(new Date());
                    financeWithdrawalService.add(financeWithdrawal);

                    //保存平台账户
                    accountPlatformDto.setCashBalance(cashBalance);
                    accountPlatformDto.setUpdateOn(new Date());
                    sysAccountPlatformService.edit(accountPlatformDto);

                    //设置第三方打款状态为打款成功
                    driverCashDto.setThirdPayStatus(DriverCashDto.THIRD_STATUS_SUCCESS);
                    //设置提现状态为提现成功
                    driverCashDto.setWithdrawalStatus(DriverCashDto.WITHDRAWAL_STATUS_SUCCESS);
                    log.info("流水号：{} 提现成功，结束记录提现流水", driverCashDto.getSerialNum());
                } else {
                    //修改第三方打款状态为失败
                    driverCashDto.setThirdPayStatus(DriverCashDto.THIRD_STATUS_FAILURE);
                    //失败原因
                    driverCashDto.setThirdReason(resultMap.get("sub_msg"));
                    log.info("流水号：{} 提现失败，失败原因：{}", driverCashDto.getSerialNum(), resultMap.get("sub_msg"));
                }
                driverCashDto.setUpdateOn(new Date());
                driverCashService.edit(driverCashDto);
                log.info("流水号：{} 查询提现结束", driverCashDto.getSerialNum());
            } catch (Exception e) {
                log.info("11111111{}",e.fillInStackTrace());
                log.error("Alipay queryCash Error. serialNum={}", driverCashDto.getSerialNum(), e);
            }
        }
        return ResponseData.buildSuccessResponse("查询支付宝打款状态成功", null);
    }

    @Override
    public ResponseData<Boolean> dataRepair(String uuid) {
        DriverCashDto driverCashDto = driverCashService.get(uuid).getData();
        log.info("流水号：{} 支付宝提现成功，开始修复提现流水", driverCashDto.getSerialNum());
        //打款成功时间
        driverCashDto.setWithdrawalFinishTime(new Date());
        //获取转账手续费 单位为分 转换成元
        driverCashDto.setThirdPoundage(0.0);
        //记录平台流水提现和提现手续费记录
        ResponseData<SysAccountPlatformDto> responseData = sysAccountPlatformService.getByAppid(driverCashDto.getAppid());
        //获取平台信息
        if (!responseData.isSuccess() || responseData.getData() == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到平台信息");
        }
        SysAccountPlatformDto accountPlatformDto = responseData.getData();
        //获取平台初始余额
        BigDecimal cashBalance = accountPlatformDto.getCashBalance();

        //提现金额
        BigDecimal amount = BigDecimal.valueOf(driverCashDto.getActualAmount());
        //保存平台提现到支付宝的流水记录
        FinanceWithdrawalDto financeWithdrawal = new FinanceWithdrawalDto();
        financeWithdrawal.setUuid(StringUtils.buildUUID());
        financeWithdrawal.setFinanceNumber(StringUtils.buildUUID());
        financeWithdrawal.setHappenTime(new Date());
        financeWithdrawal.setAmount(amount);
        financeWithdrawal.setBusinessUuid(driverCashDto.getUuid());
        financeWithdrawal.setFinanceOutflow(accountPlatformDto.getUuid());
        financeWithdrawal.setFinanceInflow("");
        financeWithdrawal.setCourse(FinanceConstant.WITHDRAWAL_TO_ALI);
        financeWithdrawal.setStartBalance(cashBalance);
        cashBalance = cashBalance.subtract(amount);
        financeWithdrawal.setFinalBalance(cashBalance);
        financeWithdrawal.setDescription("平台提现到司机支付宝账户支付" + amount + "元");
        financeWithdrawal.setCreateOn(new Date());
        financeWithdrawalService.add(financeWithdrawal);

        //保存平台账户
        accountPlatformDto.setCashBalance(cashBalance);
        accountPlatformDto.setUpdateOn(new Date());
        sysAccountPlatformService.edit(accountPlatformDto);

        //设置第三方打款状态为打款成功
        driverCashDto.setThirdPayStatus(DriverCashDto.THIRD_STATUS_SUCCESS);
        //设置提现状态为提现成功
        driverCashDto.setWithdrawalStatus(DriverCashDto.WITHDRAWAL_STATUS_SUCCESS);
        log.info("流水号：{} 支付宝提现成功，结束修复提现流水", driverCashDto.getSerialNum());
        driverCashDto.setUpdateOn(new Date());
        return driverCashService.edit(driverCashDto);
    }
}
